/*============================================================================

The Medical Imaging Interaction Toolkit (MITK)

Copyright (c) German Cancer Research Center (DKFZ)
All rights reserved.

Use of this source code is governed by a 3-clause BSD license that can be
found in the LICENSE file.

============================================================================*/


#ifndef BERRYICOMMANDSERVICE_H_
#define BERRYICOMMANDSERVICE_H_

#include "../services/berryIDisposable.h"

#include <QHash>

namespace berry {

struct IExecutionListener;
struct IHandler;
struct IElementReference;

class UIElement;
class Command;
class CommandCategory;
class ParameterizedCommand;
class ParameterType;

/**
 * <p>
 * Provides services related to the command architecture within the workbench.
 * This service can be used to access the set of commands and command
 * categories.
 * </p>
 * <p>
 * This service can be acquired from your service locator:
 * <pre>
 *  ICommandService service = (ICommandService) getSite().getService(ICommandService.class);
 * </pre>
 * <ul>
 * <li>This service is available globally.</li>
 * </ul>
 * </p>
 * @note This interface is not intended to be implemented by clients.
 * @note This interface is not intended to be extended by clients.
 */
struct BERRY_UI_QT ICommandService : public IDisposable
{

  berryObjectMacro(berry::ICommandService);

  /**
   * The identifier of the category in which all auto-generated commands will
   * appear. This value must never be <code>null</code>.
   */
  static const QString AUTOGENERATED_CATEGORY_ID();

  /**
   * Adds an execution listener to the command service. This listener will be
   * notified as commands are executed.
   * <p>
   * <b>Note:</b> listeners should be removed when no longer necessary. If
   * not, they will be removed when the IServiceLocator used to acquire this
   * service is disposed.
   * </p>
   *
   * @param listener
   *            The listener to add; must not be <code>null</code>.
   * @see #RemoveExecutionListener
   */
  virtual void AddExecutionListener(IExecutionListener* listener) = 0;

  /**
   * Sets the name and description of the category for uncategorized commands.
   * This is the category that will be returned if
   * {@link #GetCategory} is called with <code>null</code>.
   *
   * @param name
   *            The name of the category for uncategorized commands; must not
   *            be <code>null</code>.
   * @param description
   *            The description of the category for uncategorized commands;
   *            may be <code>null</code>.
   */
  virtual void DefineUncategorizedCategory(const QString& name, const QString& description) = 0;

  /**
   * <p>
   * Returns a {@link ParameterizedCommand} with a command and
   * parameterizations as specified in the provided
   * <code>serializedParameterizedCommand</code> string. The
   * <code>serializedParameterizedCommand</code> must use the format
   * returned by {@link ParameterizedCommand#Serialize} and described in the
   * Javadoc for that method.
   * </p>
   * <p>
   * If a parameter id encoded in the
   * <code>serializedParameterizedCommand</code> does not exist in the
   * encoded command, that parameter id and value are ignored. A given
   * parameter id should not be used more than once in
   * <code>serializedParameterizedCommand</code>. This will not result in
   * an exception, but the value of the parameter when the command is executed
   * cannot be specified here.
   * </p>
   * <p>
   * This method will never return <code>null</code>, however it may throw
   * an exception if there is a problem processing the serialization string or
   * the encoded command is undefined.
   * </p>
   *
   * @param serializedParameterizedCommand
   *            a <code>String</code> representing a command id and
   *            parameter ids and values
   * @return a <code>ParameterizedCommand</code> with the command and
   *         parameterizations encoded in the
   *         <code>serializedParameterizedCommand</code>
   * @throws NotDefinedException
   *             if the command indicated in
   *             <code>serializedParameterizedCommand</code> is not defined
   * @throws SerializationException
   *             if there is an error deserializing
   *             <code>serializedParameterizedCommand</code>
   * @see ParameterizedCommand#serialize()
   * @see CommandManager#deserialize(String)
   */
  virtual SmartPointer<ParameterizedCommand> Deserialize(const QString& serializedParameterizedCommand) const = 0;

  /**
   * Retrieves the category with the given identifier. If no such category
   * exists, then an undefined category with the given id is created.
   *
   * @param categoryId
   *            The identifier to find. If the category is <code>null</code>,
   *            then a category suitable for uncategorized items is defined
   *            and returned.
   * @return A category with the given identifier, either defined or
   *         undefined.
   */
  virtual SmartPointer<CommandCategory> GetCategory(const QString& categoryId) const = 0;

  /**
   * Retrieves the command with the given identifier. If no such command
   * exists, then an undefined command with the given id is created.
   *
   * @param commandId
   *            The identifier to find; must not be <code>null</code>.
   * @return A command with the given identifier, either defined or undefined.
   */
  virtual SmartPointer<Command> GetCommand(const QString& commandId) const = 0;

  /**
   * Returns the collection of all of the defined categories in the workbench.
   *
   * @return The collection of categories (<code>Category</code>) that are
   *         defined; never <code>null</code>, but may be empty.
   */
  virtual QList<SmartPointer<CommandCategory> > GetDefinedCategories() const = 0;

  /**
   * Returns the collection of the identifiers for all of the defined
   * categories in the workbench.
   *
   * @return The collection of category identifiers (<code>String</code>)
   *         that are defined; never <code>null</code>, but may be empty.
   */
  virtual QStringList GetDefinedCategoryIds() const = 0;

  /**
   * Returns the collection of the identifiers for all of the defined commands
   * in the workbench.
   *
   * @return The collection of command identifiers (<code>String</code>)
   *         that are defined; never <code>null</code>, but may be empty.
   */
  virtual QStringList GetDefinedCommandIds() const = 0;

  /**
   * Returns the collection of all of the defined commands in the workbench.
   *
   * @return The collection of commands (<code>Command</code>) that are
   *         defined; never <code>null</code>, but may be empty.
   */
  virtual QList<SmartPointer<Command> > GetDefinedCommands() const = 0;

  /**
   * Returns the collection of the identifiers for all of the defined command
   * parameter types in the workbench.
   *
   * @return The collection of command parameter type identifiers (<code>String</code>)
   *         that are defined; never <code>null</code>, but may be empty.
   */
  virtual QStringList GetDefinedParameterTypeIds() const = 0;

  /**
   * Returns the collection of all of the defined command parameter types in
   * the workbench.
   *
   * @return The collection of command parameter types (<code>ParameterType</code>)
   *         that are defined; never <code>null</code>, but may be empty.
   */
  virtual QList<SmartPointer<ParameterType> > GetDefinedParameterTypes() const = 0;

  /**
   * Gets the help context identifier for a particular command. The command's
   * handler is first checked for a help context identifier. If the handler
   * does not have a help context identifier, then the help context identifier
   * for the command is returned. If neither has a help context identifier,
   * then <code>null</code> is returned.
   *
   * @param command
   *            The command for which the help context should be retrieved;
   *            must not be <code>null</code>.
   * @return The help context identifier to use for the given command; may be
   *         <code>null</code>.
   * @throws NotDefinedException
   *             If the given command is not defined.
   */
  virtual QString GetHelpContextId(const SmartPointer<const Command>& command) const = 0;

  /**
   * Gets the help context identifier for a particular command. The command's
   * handler is first checked for a help context identifier. If the handler
   * does not have a help context identifier, then the help context identifier
   * for the command is returned. If neither has a help context identifier,
   * then <code>null</code> is returned.
   *
   * @param commandId
   *            The identifier of the command for which the help context
   *            should be retrieved; must not be <code>null</code>.
   * @return The help context identifier to use for the given command; may be
   *         <code>null</code>.
   * @throws NotDefinedException
   *             If the command with the given identifier is not defined.
   */
  virtual QString GetHelpContextId(const QString& commandId) const = 0;

  /**
   * Retrieves the command parameter type with the given identifier. If no
   * such parameter type exists, then an undefined parameter type with the
   * given id is created.
   *
   * @param parameterTypeId
   *            The identifier to find; must not be <code>null</code>.
   * @return A command parameter type with the given identifier, either
   *         defined or undefined.
   */
  virtual SmartPointer<ParameterType> GetParameterType(const QString& parameterTypeId) const = 0;

  /**
   * <p>
   * Reads the command information from the registry and the preferences. This
   * will overwrite any of the existing information in the command service.
   * This method is intended to be called during start-up. When this method
   * completes, this command service will reflect the current state of the
   * registry and preference store.
   * </p>
   */
  virtual void ReadRegistry() = 0;

  /**
   * Removes an execution listener from the command service.
   *
   * @param listener
   *            The listener to remove; must not be <code>null</code>.
   */
  virtual void RemoveExecutionListener(IExecutionListener* listener) = 0;

  /**
   * Sets the help context identifier to associate with a particular handler.
   *
   * @param handler
   *            The handler with which to register a help context identifier;
   *            must not be <code>null</code>.
   * @param helpContextId
   *            The help context identifier to register; may be
   *            <code>null</code> if the help context identifier should be
   *            removed.
   */
  virtual void SetHelpContextId(const SmartPointer<IHandler>& handler, const QString& helpContextId) = 0;

  /**
   * Register that this element accepts callbacks for this parameterized
   * command.
   * <p>
   * <b>Note:</b> elements should be removed when no longer necessary. If
   * not, they will be removed when the IServiceLocator used to acquire this
   * service is disposed.
   * </p>
   *
   * @param command
   *            The parameterized command that is already specialized. Must
   *            not be <code>null</code>.
   * @param element
   *            The callback to register for this specialized command
   *            instance. Must not be <code>null</code>.
   * @return A reference for the registered element that can be used to
   *         unregister it.
   * @throws NotDefinedException
   *             If the command included in the ParameterizedCommand is not
   *             defined, or the element is <code>null</code>.
   * @see #UnregisterElement
   */
  virtual SmartPointer<IElementReference> RegisterElementForCommand(
      const SmartPointer<ParameterizedCommand>& command,
      const SmartPointer<UIElement>& element) = 0;

  /**
   * Re-register a callback element provided by the ICommandService. This
   * element reference must not currently be held by the ICommandService. i.e.
   * it must have been removed using
   * {@link #UnregisterElement}.
   * <p>
   * <b>Note:</b> elements should be removed when no longer necessary. If
   * not, they will be removed when the IServiceLocator used to acquire this
   * service is disposed.
   * </p>
   *
   * @param elementReference
   *            The reference to re-register. Must not be <code>null</code>.
   * @see #UnregisterElement
   */
  virtual void RegisterElement(const SmartPointer<IElementReference>& elementReference) = 0;

  /**
   * Unregister an element callback. It will be removed from the
   * ICommandService. The same service that is used to register an element for
   * a command <b>must</b> be used to unregister the element.
   *
   * @param elementReference
   *            The callback reference that was provided by the command
   *            service on registration. Must not be <code>null</code>.
   */
  virtual void UnregisterElement(const SmartPointer<IElementReference>& elementReference) = 0;

  /**
   * Refresh any elements registered against the command with the given id.
   * It allows the active handler the opportunity to provide user feedback. If
   * the command is parameterized, some of the parameters can be specified to
   * help narrow down which elements to refresh.
   * <p>
   * The service locator used in registering the element can also be used to
   * scope the search. For example: if you wanted all elements for your
   * command but only within the part's workbench window, you could use:
   *
   * <pre>
   * Map filter = new HashMap();
   * filter.put(IServiceScopes.WINDOW_SCOPE, getSite().getPage()
   *    .getWorkbenchWindow());
   * commandService.refreshElements(commandId, filter);
   * </pre>
   *
   * </p>
   *
   * @param commandId
   *            The command id to refresh if it has registered eleemnts.
   * @param filter
   *            key-value pairs that can narrow down the callbacks to return.
   *            The parameters are <b>AND</b>ed together. This may be
   *            <code>null</code>.
   */
  virtual void RefreshElements(const QString& commandId, const QHash<QString, Object::Pointer>& filter) = 0;
};

}

Q_DECLARE_INTERFACE(berry::ICommandService, "org.blueberry.ui.ICommandService")

#endif /* BERRYICOMMANDSERVICE_H_ */
